#include "contact_system.h"
#include "aes.h"
#include <stdint.h>
#include <time.h>

// ---------------- 用户文件 AES-CBC 加密支持（每条记录：IV(16) + ciphertext） ----------------
// 使用 AES-128-CBC 对每条 User 结构进行加密，磁盘格式：[IV(16)][CIPHERTEXT(n)] …
// 注意：此实现仅为演示（无消息认证）。生产环境请使用带认证的 AEAD（如 AES-GCM）或 libsodium。

static const uint8_t AES_KEY_BYTES[16] = "LinkBookAESKey12"; // 16 字节（固定密钥，示例用途）

// 生成 16 字节随机 IV（简单实现：rand，若需更强随机性请使用系统 RNG）
static void gen_iv(uint8_t iv[16]) {
    srand((unsigned)time(NULL));
    for (int i = 0; i < 16; ++i) {
        iv[i] = (uint8_t)(rand() & 0xFF);
    }
}

// PKCS#7 填充；返回填充后长度（multiple of 16）
static size_t pkcs7_pad(const uint8_t *in, size_t in_len, uint8_t *out, size_t block_size) {
    size_t pad_len = block_size - (in_len % block_size);
    size_t out_len = in_len + pad_len;
    memcpy(out, in, in_len);
    for (size_t i = 0; i < pad_len; ++i) out[in_len + i] = (uint8_t)pad_len;
    return out_len;
}

// 去除 PKCS#7 填充，返回原始长度或 0 表示错误
static size_t pkcs7_unpad(uint8_t *buf, size_t buf_len, size_t block_size) {
    if (buf_len == 0 || (buf_len % block_size) != 0) return 0;
    uint8_t pad = buf[buf_len - 1];
    if (pad == 0 || pad > block_size) return 0;
    // 验证填充
    for (size_t i = 0; i < pad; ++i) {
        if (buf[buf_len - 1 - i] != pad) return 0;
    }
    return buf_len - pad;
}

// 计算加密块大小，对 sizeof(User) 的加密长度（multiple of 16）
static size_t user_encrypted_block_size() {
    size_t s = sizeof(User);
    size_t block = 16;
    return ((s + block - 1) / block) * block;
}

// 检查用户名是否存在（每条记录以 IV(16) + 密文(block) 存放）
int userExists(const char *username) {
    FILE *file = fopen("users.dat", "rb");
    if (file == NULL) return 0;

    size_t cipher_block = user_encrypted_block_size();
    uint8_t iv[16];
    uint8_t *cipher = malloc(cipher_block);
    if (!cipher) { fclose(file); return 0; }

    while (fread(iv, 1, 16, file) == 16) {
        if (fread(cipher, 1, cipher_block, file) != cipher_block) break;

        // 解密
        struct AES_ctx ctx;
        AES_init_ctx_iv(&ctx, AES_KEY_BYTES, iv);
        AES_CBC_decrypt_buffer(&ctx, cipher, cipher_block);

        size_t orig_len = pkcs7_unpad(cipher, cipher_block, 16);
        if (orig_len == 0 || orig_len > sizeof(User)) continue; // 解码错误，跳过

        User user;
        memcpy(&user, cipher, sizeof(User));
        if (strcmp(user.username, username) == 0) {
            free(cipher);
            fclose(file);
            return 1;
        }
    }
    free(cipher);
    fclose(file);
    return 0;
}

// 保存用户信息到文件（每条记录写 IV + ciphertext）
void saveUserToFile(const User *user) {
    size_t block = user_encrypted_block_size();
    uint8_t *plain = malloc(block);
    uint8_t *cipher = malloc(block);
    if (!plain || !cipher) {
        printf("内存不足，无法保存用户\n");
        free(plain); free(cipher);
        return;
    }

    // 拷贝并填充
    memset(plain, 0, block);
    memcpy(plain, user, sizeof(User));
    size_t enc_len = pkcs7_pad(plain, sizeof(User), plain, 16);

    uint8_t iv[16];
    gen_iv(iv);

    struct AES_ctx ctx;
    AES_init_ctx_iv(&ctx, AES_KEY_BYTES, iv);
    memcpy(cipher, plain, enc_len);
    AES_CBC_encrypt_buffer(&ctx, cipher, enc_len);

    FILE *file = fopen("users.dat", "ab");
    if (file == NULL) {
        printf("无法打开用户文件进行写入！\n");
        free(plain); free(cipher);
        return;
    }
    fwrite(iv, 1, 16, file);
    fwrite(cipher, 1, enc_len, file);
    fclose(file);

    free(plain); free(cipher);
}

// 从文件加载用户数据（初始化用户文件）
void loadUsersFromFile() {
    FILE *file = fopen("users.dat", "rb");  // 以二进制只读模式打开
    if (file == NULL) {
        file = fopen("users.dat", "wb");  // 文件不存在则创建新文件
        if (file) fclose(file);
        return;
    }
    fclose(file);
}

// 导出通讯录到文本文件
void exportContactsToText(ContactNode *head) {
    if (head == NULL || head->next == head) {
        printf("通讯录为空，无法导出！\n");
        return;
    }
    FILE *file = fopen("contacts_export.txt", "w");  // 以写入模式打开导出文件
    if (file == NULL) {
        printf("文件创建失败！\n");
        return;
    }

    // 写入文件头部信息
    fprintf(file, "通讯录导出数据\n");
    fprintf(file, "生成时间: %s\n", getCurrentTime()); // 获取时间戳
    fprintf(file, "========================================\n");
    fprintf(file, "%-4s %-10s %-4s %-12s\n", "ID", "姓名", "性别", "电话"); 
    fprintf(file, "----------------------------------------\n");
    
    // 遍历双向循环链表，写入每个联系人信息
    ContactNode *cur = head->next;
    while (cur != head) {
        fprintf(file, "%-4d %-10s %-4c %-12s\n", cur->id, cur->name, cur->gender, cur->phone);
        cur = cur->next;
    }
    fclose(file);
    printf("通讯录已成功导出到文件 contacts_export.txt\n");
}

// 保存通讯录到文件
void saveContactsToFile(ContactNode *head) {
    if (head == NULL) return;
    FILE *file = fopen("contacts.txt", "w");  // 以写入模式打开文件
    if (file == NULL) {
        printf("无法打开 contacts.txt 进行写入！\n");
        return;
    }
    
    // 遍历链表，将每个联系人信息写入文件（制表符分隔）
    ContactNode *cur = head->next;
    while (cur != head) {
        fprintf(file, "%d\t%s\t%c\t%s\n", cur->id, cur->name, cur->gender, cur->phone);
        cur = cur->next;
    }
    fclose(file);
}

// 从文件加载通讯录数据
void loadContactsFromFile(ContactNode *head) {
    if (head == NULL) return;
    FILE *file = fopen("contacts.txt", "r");  // 以只读模式打开文件
    if (file == NULL) return;

    // 去除末尾回车符/换行符和空格
    auto_trim:
    ;
    char line[256];  // 缓冲区存储每行数据
    
    // 逐行读取文件内容
    while (fgets(line, sizeof(line), file)) {
        // 移除行尾的换行符和回车符
        size_t len = strlen(line);
        while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r')) {
            line[--len] = '\0';
        } 

        int id = 0;
        char name[MAX_NAME] = {0};
        char phone[MAX_PHONE] = {0};
        char gender = 0;

        // 使用制表符分隔解析行数据（姓名可能包含空格）
        int matched = sscanf(line, "%d\t%49[^\t]\t %c\t%14s", &id, name, &gender, phone);
        if (matched == 4) {
            // 去除解析字段中可能存在的尾部空格或回车符
            size_t n;
            n = strlen(name);
            while (n > 0 && (name[n-1] == '\r' || name[n-1] == '\n' || name[n-1] == ' ')) name[--n] = '\0';
            n = strlen(phone);
            while (n > 0 && (phone[n-1] == '\r' || phone[n-1] == '\n' || phone[n-1] == ' ')) phone[--n] = '\0';

            // 创建新节点并插入到双向循环链表中
            ContactNode *node = createNode(id, name, gender, phone);
            if (!node) continue;
            node->next = head; 
            node->prior = head->prior; 
            head->prior->next = node; 
            head->prior = node;
        } else {
            // 备用方案：空格分隔解析（如果文件格式不同）
            matched = sscanf(line, "%d %49s %c %14s", &id, name, &gender, phone);
            if (matched == 4) {
                ContactNode *node = createNode(id, name, gender, phone);
                if (!node) continue;
                node->next = head; 
                node->prior = head->prior; 
                head->prior->next = node; 
                head->prior = node;
            } else {
                // 忽略格式错误的行
                continue;
            }
        }
    }
    fclose(file);
}